from Commons import *

class Item:#an object in inventory
    color = L.white
    character = ' '
    def name(self):#return the item's name
        return "Widget"
    def __init__(self,color = L.white,character = 255):
        self.color = color#the object's color
        self.character = character#the object's character
    def equipSlot(self):
        return EQ_NONE
    def canRange(self):#can the weapon shoot ranged projectiles?
        return False
    def dropScript(self):#a drop script for the item when it touches the ground
        pass
    def pickupScript(self):#a pick-up script for the item when it is picked up
        pass
    #a usage script for the item when it is used
    #return false if the item isn't used up, then True if it took an action
    def useScript(self,user):
        addMessage("You can't use the "+self.name(),L.red)
        return (False,False)

class Armor(Item):#armor in inventory
    defenseboost = 0
    armorbonus = 0
    def name(self):
        return "Armor"
    def __init__(self,color,character):
        Item.__init__(self,color,character)
    def equipSlot(self):
        return EQ_ARMOR

class Weapon(Item):#a weapon in inventory
    attackboost = 0
    damagebonus = 0
    def name(self):
        return "Weapon"
    def __init__(self,color,character):
        Item.__init__(self,color,character)
    def equipSlot(self):
        return EQ_WEAPON

class RangedProjectile():#the map object that actually travels on the map to hit targets
    projectilespeed = 100
    color = L.white
    character = '*'
    def __init__(self,startx,starty,endx,endy):
        self.x = startx
        self.y = starty
        self.sx = startx
        self.sy = starty
        self.ex = endx
        self.ey = endy
    #cast a line from the start to the end, travel a step on it, and see if anything is hit
    def collisionEffect(self,creature):#a creature hops into the path of the projectile
        addMessage("You shoot "+creature.descriptor,L.white)
        creature.loseHealth(6)#take damage
        Game()[A_MAP][L_RAN].destroyObject(self)#delete this
    def act(self):#the ranged object acts
        L.line_init(self.sx,self.sy,self.ex,self.ey)
        x, y = self.sx, self.sy
        while (not x is None):
            
            if (x == self.x and y == self.y):#if this is the position
                
                self.x, self.y = L.line_step()#the new position is at the line step
                if ((self.x,self.y) == (None,None)):#if it moves nowhere
                    Game()[A_MAP][L_RAN].destroyObject(self)#delete this
                    return self.projectilespeed
                #modify the object's display
                Game()[A_MAP][L_RAN].modifyObjectDisplay(self,self.x,self.y)
                if (Game()[A_MAP][L_CRE][(self.x,self.y)] != None):#if there is a creature
                    self.collisionEffect(Game()[A_MAP][L_CRE][(self.x,self.y)])#he sprung into the trap
                    
                return self.projectilespeed#done with movement
            x, y = L.line_step()
        #end of the line -- should not access
        Game()[A_MAP][L_RAN].destroyObject(self)#delete this
        return self.projectilespeed#done
                
class RangedWeapon(Weapon):
    charges = 40
    def name(self):
        return "Ranged Weapon"
    def __init__(self,color,character):
        Weapon.__init__(self,color,character)
    def canRange(self):#ranged weapon
        return True
    #update the ranged targeting for the weapon based on the mouse position
    def handleRangedTargeting(self,mouse):
        centerx, centery = 7, 7#constant, change if the player position changes
        p = Game()[A_PLAYER]#player position
        L.console_clear(ranged_console)#clear the ranged console
        L.line_init(centerx,centery,mouse.cx,mouse.cy)#make the console
        x, y = L.line_step()
        while (not x is None):#keep stepping through as long as there is a coordinate
            targetsquare = (x-centerx+p.x,y-centery+p.y)#the map coordinate
            if (not Game()[A_MAP][targetsquare].lit):#if out of FOV
                return
            L.console_set_back(ranged_console,x,y,L.white,L.BKGND_SET)
            
            if (Game()[A_MAP][targetsquare].block_movement or Game()[A_MAP][L_CRE][targetsquare] != None):#if it is blocked
                return#stop drawing
            x, y = L.line_step()
    def fireWeapon(self,mouse):
        pass

class Trap:
    color = L.violet
    character = '^'
    def collisionEffect(self,creature):
        addMessage("The trap hits the "+creature.descriptor,L.white)
        creature.loseHealth(6)#take damage
        Game()[A_MAP][L_RAN].destroyObject(self)#delete this

class GroundInventory:#a group of objects on the ground
    def __init__(self,item=None):
        self.items = []
        if (item != None):
            self.addItem(item)
    def addItem(self,item):#add an item and get the new character
        self.items.append(item)
        self.color = item.color
        self.character = item.character
        item.dropScript()#do the drop script
        

    def removeItem(self,item):
        if (item not in self.items):#item not here
            raise KeyError
        self.items.remove(item)
        if (len(self.items) > 0):#set a new inventory, based on the item in front
            self.color = item[len(self.items)-1].color
            self.character = item[len(self.items)-1].character
            return False#still an inventory
        self.color = L.white
        self.character = ' '
        return True#empty inventory

class CreatureInventory:#a group of objects carried by a creature
    order = [1,2,3,4,5,6,7,8,9,0]#order for the inventory slots
    equipslots = [EQ_ARMOR, EQ_WEAPON]#the equipment slots
    def __init__(self,inventoryuser):
        self.items = {}
        self.inventoryuser = inventoryuser#the owner of the inventory
        self.equipeditems = {}#the equipped items
        for value in self.order:#make each of the slots None
            self.items[value] = None
        for value in self.equipslots:#make each of the equipment slots None
            self.equipeditems[value] = None
    def __getitem__(self,key):
        if (key in self.equipslots):#item is equiped
            return self.equipeditems[key]
        elif (key in self.order):
            return self.items[key]
        else:
            raise KeyError
    def addItem(self,item):#add an item
        for value in self.order:#for each value
            if (self.items[value] == None):#empty slot and nothing filled
                self.items[value] = item#assign item
                return value#found
        return -1#no space
    def itemExists(self,key):#checks whether a particular key has an item
        if (key not in self.order):#key should be known
            print "Key not found!"
            return False
        if (self.items[key] == None):#no item in slot
            return False
        return True
    def removeItem(self,key):#remove an item based on key
        if (not self.itemExists(key)):#item does not exist
            return None
        #remove and return the item
        returneditem = self.items[key]
        for thekey in self.equipslots:#unequip items if necessary
            if (self.equipeditems[thekey] == self.items[key]):
                self.equipeditems[thekey] = None
        self.items[key] = None
        return returneditem
    def removeEverything(self):#remove everything from the inventory and return the items
        removeditems = []
        for key in self.order:
            removeditem = self.removeItem(key)
            if (removeditem != None):#if the removed item is not nothing
                removeditems.append(removeditem)
        return removeditems
    def useItem(self,key):
        if (not self.itemExists(key)):#item does not exist
            return False
        #activate the use script, and delete it if it returns true (used up)
        returnval = self.items[key].useScript(self.inventoryuser)
        if (returnval[0]):#delete the item
            self.removeItem(key)
        return returnval[1]#did it take a turn?
    def equipItem(self,key):
        if (not self.itemExists(key)):#item does not exist
            return False
        if (self.items[key].equipSlot() == EQ_NONE):#no equip slot
            return False#cannot be equipped
        if (self.items[key] == self.equipeditems[self.items[key].equipSlot()]):#if equipping the same item
            return False#does not take a turn
        #equip the item
        self.equipeditems[self.items[key].equipSlot()] = self.items[key]
        return True
    def inventorySpotsLeft(self):#the number of inventory spots open
        spots = 0
        for value in self.order:
            if (self.items[value] == None):#spot
                spots += 1
        return spots
    def inventoryName(self,key):#the inventory name of an item
        name = self.items[key].name()
        if (self.equipeditems[EQ_WEAPON] == self.items[key]):#show that it is wielded
            name += " (wielded)"
        if (self.equipeditems[EQ_ARMOR] == self.items[key]):
            name += " (worn)"
        return name